package com.jh.fcsm.service.sys.impl;

import com.jh.fcsm.beans.sys.SysRole;
import com.jh.fcsm.beans.sys.SysUser;
import com.jh.fcsm.beans.sys.vo.LoginUser;
import com.jh.fcsm.common.exception.ServiceException;
import com.jh.fcsm.common.redis.RedisUtil;
import com.jh.fcsm.constant.CommonConstant;
import com.jh.fcsm.constant.Constant;
import com.jh.fcsm.constant.RedisConstant;
import com.jh.fcsm.constant.TokenConstants;
import com.jh.fcsm.service.sys.LoginAttemptService;
import com.jh.fcsm.service.sys.SysUserService;
import com.jh.fcsm.util.http.IpUtils;
import com.jh.fcsm.util.security.RSAEncrypt;
import com.jh.fcsm.util.txt.StringUtils;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;

/**
 * spring security登陆处理
 *
 * @author szx
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private SysUserService userService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private LoginAttemptService loginAttemptService;
    @Autowired
    private HttpServletRequest request;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        String ip = IpUtils.getIpAddr(request);
        if (loginAttemptService.isBlocked(ip)) {
            throw new ServiceException("登录次数过多,请十分钟后再试!");
        }
        // username参数值由三个部分组成 username + @jh@ + code + @jh@ + uuid
        String[] codeArr = new String[0];
        try {
            codeArr = RSAEncrypt.privateKeyDecrypt(username, TokenConstants.PRIVATE_KEY).split("@jh@");
        } catch (Exception e) {
            throw new ServiceException("非法请求");
        }
        // 用户名
        username = codeArr[0];
        // 验证码
        String validCode = codeArr[1];
        // 验证码在redis中的标识
        String guid = codeArr[2];
        // 校验验证码
        validateCaptcha(validCode, guid);
        try {
            // 获取用户信息
            SysUser sysUser = userService.getUserByUsername(username);
            // 校验用户合法性
            validateUser(sysUser);

            LoginUser loginUser = new LoginUser();
            BeanUtils.copyProperties(sysUser, loginUser);
            // 获取角色
            List<SysRole> sysRoles = userService.listRolesByUserId(sysUser.getId());
            loginUser.setSysRoles(sysRoles);
            // 获取权限
            Set<String> permissions = userService.listElementByUserId(sysUser.getId(), sysRoles);
            loginUser.setPermissions(permissions);

            //如果有不需要google验证帐号的在这里判断
            for (SysRole role : sysRoles) {
                if (CommonConstant.FLAG_YES.equals(role.getDynamicVer())) {
                    loginUser.setPassword(getValue(loginUser.getSalt())+ TokenConstants.GOOGLE_AUTHENTICATOR_FLAG+loginUser.getPassword());
                    break;
                }
            }

            return loginUser;
        }catch (Exception e){
            throw new BadCredentialsException("用户名或密码错误");
        }
    }
    private  String  getValue(String v){
        if(StringUtils.isEmpty(v)){
            return "";
        }
        return v;
    }

    /**
     * 校验用户合法性
     *
     * @param sysUser 登录用户
     */
    private void validateUser(SysUser sysUser) {
        if (sysUser == null) {
            throw new AuthenticationCredentialsNotFoundException("用户名或密码错误");
        } else if (sysUser.getEnabled() == Constant.DISABLED) {
            throw new DisabledException("用户已作废");
        }
    }

    /**
     * 验证码校验
     *
     * @param validCode 验证码
     * @param guid      验证码标识
     */
    private void validateCaptcha(String validCode, String guid) {
        Object codeObj = redisUtil.get(RedisConstant.VALID_CODE_KEY + guid);
        // 验证码过期
        if (codeObj == null) {
            throw new AuthenticationCredentialsNotFoundException("验证码已过期");
        }
        // 验证码错误
        if (!validCode.equalsIgnoreCase(codeObj.toString())) {
            throw new AuthenticationCredentialsNotFoundException("验证码错误");
        }
    }
}
